﻿#pragma once
#include <string>
#include <vector>
#include <atomic>
#include <iostream>
#include <opencv2/opencv.hpp>
#include <stdint.h>

#include "stream/total_struct.h"
#include "auth_struct.h"

namespace ai {


enum ModelType {
  model_none = 0,
  
  model_text_det=100,                         // 同时支持tiny

  model_text_rec=200,             // 序列识别

  model_det= 300,

  model_seg = 400,

  model_cls = 500,
  model_cls_video = 550,

  model_plate_rec = 600,

  model_face_det = 700,
  model_face_rec = 710,

};

typedef struct VPSInfo {
  VPSInfo() {}
  VPSInfo(int cam_idx, int ed_chn, int vps_grp, int vps_chn):
    idx(cam_idx), enc_dec_chn(ed_chn), VpsGrp(vps_grp), vpsChn(vps_chn) {}
  int idx;
  int enc_dec_chn;
  int VpsGrp;
  int vpsChn;
};

struct BaseInfo
{
  BaseInfo():score(0),
              class_idx(0),
              category("") {}
  BaseInfo(float score, 
            int class_idx,
            std::string cate):
              score(score), 
              class_idx(class_idx),
              category(cate) {}
  BaseInfo(const BaseInfo& cci) {
    *this = operator=(cci);
  }
  BaseInfo& operator=(const BaseInfo& cci) {
    if (this == &cci) { return *this; }
    this->score = cci.score;
    this->class_idx = cci.class_idx;
    this->category = cci.category;
    return *this;
  }
  float score;
  int class_idx;
  std::string category;
};


struct ClsInfo : public BaseInfo
{
  ClsInfo():BaseInfo() {}
  ClsInfo(float score, int class_idx, std::string cate):
              BaseInfo(score, class_idx, cate) {}
  std::vector<float> top5_score;
  std::vector<int> top5_class;
};

struct DetInfo : public BaseInfo
{   
  DetInfo():BaseInfo(),
              det_box(cv::Rect()),
              mask(cv::Mat()) {}
  DetInfo(float score,
              int class_idx, 
              cv::Rect box,
              std::string cate=std::string(),
              cv::Mat m=cv::Mat()):
              BaseInfo(score, class_idx, cate),
              det_box(box) {
    mask = m.clone();
  }
  DetInfo(const DetInfo& cci) {
    *this = operator=(cci);
  }
  DetInfo& operator=(const DetInfo& cci) {
    if (this == &cci) { return *this; }
    ai::BaseInfo::operator=(cci);
    this->det_box = cci.det_box;
    this->det_boxf = cci.det_boxf;
    this->mask = cci.mask;
    this->points = cci.points;
    this->kps = cci.kps;
    return *this;
  }
  bool operator==(const DetInfo& cci) const {
    return det_box == cci.det_box;
  }
  bool operator!=(const DetInfo& cci) const {
    return !(*this == cci);
  }
  bool operator<(const DetInfo& val) const {
    if (det_box.tl() != val.det_box.tl())
      return det_box.x == val.det_box.x ? det_box.y < val.det_box.y : det_box.x < val.det_box.x;
    else
      return det_box.br().x == val.det_box.br().x ? det_box.br().y < val.det_box.br().y : det_box.br().x < val.det_box.br().x;
  }
  cv::Rect det_box;
  cv::Rect2f det_boxf;

  cv::Mat mask;
  std::vector<cv::Point2f> points; // x,y Landmark
                                    //包含五个点，眼睛、鼻尖、嘴角，输入图坐标
  std::vector<float> kps;   // pose 关键点
                            //人脸特征检测信息
};


struct TextDetInfo : public DetInfo 
{
  TextDetInfo():DetInfo(),
                  rrect(cv::RotatedRect()) {}
  TextDetInfo(cv::RotatedRect &r, const std::vector<cv::Point> &vp,float s, std::vector<float> &ss, std::vector<int> &cs, std::vector<int> &groups_idx):
    DetInfo(s, 0, cv::Rect(), "") {
    rrect = r;
    for (auto p:vp){four_points.push_back(p);}
  }
  virtual ~TextDetInfo() {
  }
  TextDetInfo(const std::vector<cv::Point> &vp, float s):
                  DetInfo(s, 0, cv::Rect(), "") {
    for (auto p:vp){four_points.push_back(p);}
  }
  TextDetInfo(const std::vector<cv::Point> &vp, float s, std::vector<std::vector<cv::Point>> &tp):
                  DetInfo(s, 0, cv::Rect(), "") {
    for (auto p:vp){four_points.push_back(p);}
    for (auto p:tp){proposal_points.push_back(p);}
  }
  // 原始 
  // four_points  lt, rt, rb, lb
  std::vector<cv::Point> four_points;
  
  // 附带数据 
  std::vector<std::vector<cv::Point>> proposal_points;   // dilate four_points;

  // 额外扩展数据
  // rotated_rect
  cv::RotatedRect rrect;
  std::vector<cv::RotatedRect> proposal_rrects;  // dilate rrect;
  int double_plate;       // 是否是双层车牌
};

struct TextRecInfo : public BaseInfo {
  TextRecInfo():BaseInfo(), 
                  det_score(0.),
                  text("") {}
  TextRecInfo(float rs, std::string text):
                  BaseInfo(rs, 0, ""), 
                  text(text){}
  TextRecInfo(float rs, std::string text, std::string color):
                  BaseInfo(rs, 0, ""), 
                  text(text), color(color){}
  TextRecInfo(float ds, cv::RotatedRect &rr,
                  std::vector<cv::Point> &fp,
                  TextRecInfo &tri):
                  BaseInfo()
  {
      det_score = ds;
      score = tri.score;
      text = tri.text;
      for (auto p : fp){four_points.push_back(p);}
      rrect = rr;
  }
  float det_score;
  std::string text;
  std::string color;    // 车牌颜色
  
  // four_points  lt, rt, rb, lb
  std::vector<cv::Point> four_points;
  cv::RotatedRect rrect;
};

class DetectRectSort
{
public:
	DetectRectSort(int i = 0, bool b = true) :dis(i), flag(b) {}

	bool operator()(const DetInfo &p1, const DetInfo &p2)const
	{
		if (flag)
			return std::abs(p1.det_box.y - p2.det_box.y) < dis ? p1.det_box.x < p2.det_box.x : p1.det_box.y < p2.det_box.y;
		else
			return std::abs(p1.det_box.x - p2.det_box.x) < dis ? p1.det_box.y < p2.det_box.y : p1.det_box.x < p2.det_box.x;
	}

private:
	int dis;
	bool flag;	//0为横向，1为纵向
};


typedef struct ModuleInfo {
  ModuleInfo():mdl_idx(-1) {}
  ModuleInfo(int mdl_idx,
                  int detectType):
                  mdl_idx(mdl_idx),
                  algoType(detectType){}

  std::string name;                       // 模块名称
  std::string type;                       // 模块类型
  
  int mdl_idx;
  int algoType;                 // 算法类型

};

// struct authModelLabel{
//   authModelLabel(){}
//   authModelLabel(const authModelLabel& mi){
//     *this = operator=(mi);
//   }
//   authModelLabel& operator=(const authModelLabel& mi) {
//     if (this == &mi) { return *this; }
//     this->model_id = mi.model_id;
//     this->auth_labeles = mi.auth_labeles;
//     return *this;
//   }
//   std::string model_id;
//   std::vector<std::string> auth_labeles;
// };

struct InitModelData {
	InitModelData() {}
  InitModelData(std::string model_dir,
                  std::string model_prefix,
                  std::string model_id,
                  std::string model_name,
                  ModelType model_type,
                  int model_index,
                  std::string mdoel_cfg_path):
                  model_dir(model_dir),
                  model_prefix(model_prefix),
                  model_id(model_id),
                  model_name(model_name), 
                  model_type(model_type), 
                  model_index(model_index), 
                  mdoel_cfg_path(mdoel_cfg_path){}
  
  InitModelData(std::string model_dir, 
                  std::string model_prefix,
                  std::string model_name, 
                  ModelType model_type,
                  int gpu_idx,
                  float gpu_memory_fraction, 
                  std::string model_id,
                  std::string label_name="label.txt",
                  int squeence_length=0,
                  int input_width=0,
                  int input_height=0,
                  bool allow_soft_placement=true):

                  model_dir(model_dir), 
                  model_prefix(model_prefix),
                  model_name(model_name), 
                  model_type(model_type), 
                  model_id(model_id),
                  gpu_idx(gpu_idx),
                  gpu_memory_fraction(gpu_memory_fraction),
                  label_name(label_name),
                  squeence_length(squeence_length),
                  allow_soft_placement(allow_soft_placement),
                  input_width(input_width),
                  input_height(input_height)
                  {}

  std::string model_dir;                  // 模型存放目录                             /home/model
  std::string model_prefix;               // 模型存放目录前缀                          /det/base
  std::string model_id;               // 模型id
  std::string model_name;                 // 模型名称                                 BaseScene
  ModelType model_type;                         // 模型类别 在ModelType中体现
  int model_index;                          // 模型索引号, 在调用识别函数时需要再次使用

  int gpu_idx;                            // 在第几块gpu 上加载当前模型
  float gpu_memory_fraction;              // 当前模型占用gpu 内存比例 
  
  std::string label_name;                 // 标签文件
  int squeence_length;                    // model_crnn 的输入序列最小长度
  bool allow_soft_placement;              // 允许使用cpu
  int input_width;                        // 输入图像宽
  int input_height;                        // 输入图像高

  std::string mdoel_cfg_path;   //模型的id对应的cfg数据

};


struct InferResult
{
  InferResult(): source_id(-1), infer_id(-1){}
  InferResult(int source_id, int infer_id): source_id(source_id), infer_id(infer_id){}
  ~InferResult(){
  }
  InferResult(const InferResult& blob) {
    *this = operator=(blob);
  }
  InferResult& operator=(const InferResult& blob) {
    if (this == &blob) { return *this; }
    source_id = blob.source_id;
    infer_id = blob.infer_id;
    infer_res = blob.infer_res;
    time = blob.time;
    return *this;
  }
  // 数据源id 由上层设置
  int source_id;
  // 推理id 由推理框架设置
  int infer_id;
  std::vector<ai::BaseInfo*> infer_res;

  // 用于记录当前结果产生的时间 超过一定时间后 上层手动删除此条结果
  int64_t time;
};

}   // namespace hb 
